<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" content="maximum-scale=1.0, user-scalable=0">
        <title>画板</title>
        <style type="text/css">
        
        
* {
    margin: 0;
    border: 0;
    padding: 0;
    background-color: white;
}

canvas {
    border: 1px solid red;
    user-select: none;
    position: fixed;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
}

.colorpicker {
    border: 0.5vw solid white;
    border-radius: 50%;
    margin: 0 1vw;
    padding-top: 8%;
    box-shadow: 0.2vw 0.2vw 1vw rgba(0, 0, 0, 0.5);
    flex: 1 1 10vw;
}

.colorpanel .clearbutton {
    border: 0.5vw solid white;
    border-radius: 50%;
    margin: 0 1vw;
    box-shadow: 0.2vw 0.2vw 1vw rgba(0, 0, 0, 0.5);
    flex: 1 1 10vw;
    font-size: 5vw;
}

.colorpicker.chosen {
    transform: scale(1.2, 1.2);
}

.colorpanel {
    position: fixed;
    top: 5vw;
    left: 10%;
    z-index: 999;
    display: flex;
    width: 80%;
}

.info {
    position: fixed;
    bottom: 0;
    left: 0;
    z-index: 9999;
    width: 100%;
    text-align: center;
}


        </style>
    </head>
     
    <body>
        <div id="root" />
        
        <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
        <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
        
        <script>
        
        
"use strict";

function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }

function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }

function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }

function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }

function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }

function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }

function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }

function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }

function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }

var Painter = function Painter(_ref) {
  var width = _ref.width,
      height = _ref.height;
  var canvasRef = React.useRef();

  var _React$useState = React.useState([0, 0]),
      _React$useState2 = _slicedToArray(_React$useState, 2),
      currentPosition = _React$useState2[0],
      setCurrentPosition = _React$useState2[1];

  var _React$useState3 = React.useState(false),
      _React$useState4 = _slicedToArray(_React$useState3, 2),
      isDrawing = _React$useState4[0],
      setIsDrawing = _React$useState4[1];

  var _React$useState5 = React.useState([]),
      _React$useState6 = _slicedToArray(_React$useState5, 2),
      points = _React$useState6[0],
      setPoints = _React$useState6[1];

  var _React$useState7 = React.useState(),
      _React$useState8 = _slicedToArray(_React$useState7, 2),
      websocket = _React$useState8[0],
      setWebsocket = _React$useState8[1];

  var _React$useState9 = React.useState(0),
      _React$useState10 = _slicedToArray(_React$useState9, 2),
      userCount = _React$useState10[0],
      setUserCount = _React$useState10[1];

  var red = [255, 0, 0, 255],
      orange = [255, 165, 0, 255],
      yellow = [255, 255, 0, 255],
      green = [0, 255, 0, 255],
      cyan = [0, 255, 255, 255],
      blue = [0, 50, 255, 255],
      purple = [139, 0, 255, 255];

  var _React$useState11 = React.useState(red),
      _React$useState12 = _slicedToArray(_React$useState11, 2),
      color = _React$useState12[0],
      setColor = _React$useState12[1];

  var _React$useState13 = React.useState(5),
      _React$useState14 = _slicedToArray(_React$useState13, 2),
      size = _React$useState14[0],
      setSize = _React$useState14[1];

  React.useEffect(function () {
    setWebsocket(new WebSocket("wss://34077828v5.oicp.vip/"));
  }, []);
  React.useEffect(function () {
    if (websocket === undefined) {
      return;
    }

    websocket.onmessage = function (e) {
      var data = JSON.parse(e.data);

      if (data.type == "draw") {
        var _JSON$parse = JSON.parse(data.data),
            curve = _JSON$parse.curve,
            _color = _JSON$parse.color,
            _size = _JSON$parse.size;

        drawCurve(curve, _color, _size);
      } else if (data.type == "users") {
        setUserCount(data.count);
      }
    };

    return function () {
      websocket.close();
    };
  }, [websocket]);

  var drawPoint = function drawPoint(x, y) {
    // skip if no enough points or points are too close
    if (points.length !== 0) {
      var last = points[points.length - 1];

      if (Math.abs(last[0] - x) < size && Math.abs(last[1] - y) < size) {
        return;
      }
    }

    points.push([x, y]);
    setCurrentPosition([x, y]);

    if (points.length > 5) {
      update();
    }
  };

  var update = function update() {
    if (points.length <= 1) {
      return;
    }

    var curve = Array.from(points);

    if (websocket !== undefined && websocket.send !== undefined) {
      websocket.send(JSON.stringify({
        curve: curve,
        color: color,
        size: size
      }));
    } else {
      console.error('fail to send ' + JSON.stringify({
        curve: curve,
        color: color,
        size: size
      }), websocket);
    }

    drawCurve(curve, color, size);
    points.length = 0;
    points.push(curve[curve.length - 1]);
  };

  var drawCurve = function drawCurve(curve) {
    var color = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [255, 0, 0, 255];
    var size = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;

    if (curve === undefined) {
      return;
    }

    var ctx = canvasRef.current.getContext('2d');
    var imageData = ctx.createImageData(size, size);
    var data = imageData.data;

    for (var i = 0; i < size * size * 4; i += 4) {
      data[i] = color[0];
      data[i + 1] = color[1];
      data[i + 2] = color[2];
      data[i + 3] = color[3];
    }

    for (var _i2 = 0; _i2 < curve.length - 1; ++_i2) {
      var start = curve[_i2],
          end = curve[_i2 + 1];
      var len = Math.max(Math.abs(start[0] - end[0]), Math.abs(start[1] - end[1]));

      for (var j = 0; j < len; ++j) {
        ctx.putImageData(imageData, start[0] + (end[0] - start[0]) * j / len, start[1] + (end[1] - start[1]) * j / len);
      }
    }
  };

  var convertCoordinates = function convertCoordinates(x, y) {
    return [width * x / document.documentElement.clientWidth, height * y / document.documentElement.clientHeight];
  };

  var handleMouseMove = function handleMouseMove(e) {
    if (isDrawing) drawPoint.apply(void 0, _toConsumableArray(convertCoordinates(e.clientX, e.clientY)));
  };

  var handleTouchMove = function handleTouchMove(e) {
    if (isDrawing) drawPoint.apply(void 0, _toConsumableArray(convertCoordinates(e.touches[0].clientX, e.touches[0].clientY)));
  };

  var startDrawing = function startDrawing() {
    setIsDrawing(true);
  };

  var stopDrawing = function stopDrawing() {
    setIsDrawing(false);
    update();
    points.length = 0;
  };

  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("canvas", {
    ref: canvasRef,
    onMouseMove: handleMouseMove,
    onTouchMove: handleTouchMove,
    onMouseDown: startDrawing,
    onTouchStart: startDrawing,
    onMouseUp: stopDrawing,
    onTouchEnd: stopDrawing,
    width: width,
    height: height
  }), /*#__PURE__*/React.createElement("div", {
    className: "colorpanel"
  }, /*#__PURE__*/React.createElement(ColorPicker, {
    targetColor: red,
    setColor: setColor,
    currentColor: color
  }), /*#__PURE__*/React.createElement(ColorPicker, {
    targetColor: orange,
    setColor: setColor,
    currentColor: color
  }), /*#__PURE__*/React.createElement(ColorPicker, {
    targetColor: yellow,
    setColor: setColor,
    currentColor: color
  }), /*#__PURE__*/React.createElement(ColorPicker, {
    targetColor: green,
    setColor: setColor,
    currentColor: color
  }), /*#__PURE__*/React.createElement(ColorPicker, {
    targetColor: cyan,
    setColor: setColor,
    currentColor: color
  }), /*#__PURE__*/React.createElement(ColorPicker, {
    targetColor: blue,
    setColor: setColor,
    currentColor: color
  }), /*#__PURE__*/React.createElement(ColorPicker, {
    targetColor: purple,
    setColor: setColor,
    currentColor: color
  }), /*#__PURE__*/React.createElement("button", {
    class: "clearbutton",
    onClick: function onClick() {
      var ctx = canvasRef.current.getContext('2d');
      var imageData = ctx.createImageData(width, height);

      for (var i = 0; i < imageData.data.length; i += 4) {
        imageData.data[i] = 255;
        imageData.data[i + 1] = 255;
        imageData.data[i + 2] = 255;
        imageData.data[i + 3] = 255;
      }

      ctx.putImageData(imageData, 0, 0);
    }
  }, "X")), /*#__PURE__*/React.createElement("div", {
    className: "info"
  }, /*#__PURE__*/React.createElement("p", null, "在线人数：" + userCount)));
};

var ColorPicker = function ColorPicker(_ref2) {
  var targetColor = _ref2.targetColor,
      setColor = _ref2.setColor,
      currentColor = _ref2.currentColor;

  var isSameColor = function isSameColor(color1, color2) {
    for (var i = 0; i < 4; ++i) {
      if (color1[i] !== color2[i]) {
        return false;
      }
    }

    return true;
  };

  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("button", {
    className: 'colorpicker ' + (isSameColor(targetColor, currentColor) ? 'chosen' : '999'),
    onClick: function onClick(e) {
      setColor(targetColor);
    },
    style: {
      backgroundColor: "rgba(".concat(targetColor[0], ", ").concat(targetColor[1], ", ").concat(targetColor[2], ", ").concat(targetColor[3], ")")
    }
  }));
};

ReactDOM.render( /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Painter, {
  width: 480,
  height: 800
})), document.getElementById('root'));

        
        </script>
    </body>
     
</html>